/*
 * Copyright 2002-2007 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.beans.factory;

import org.springframework.beans.BeansException;

/**
 * 访问Spring bean容器的根接口。这是对一个bean容器的basic client view。如果有其他具体的需求，可以访问例如
 * {@link ListableBeanFactory} and
 * {@link org.springframework.beans.factory.config.ConfigurableBeanFactory}
 * 等这些接口。
 * <p>
 * 这个接口的实现类可以持有一系列的bena定义，每一个bean由一个String类型的名称加以区分。根据bean的定义，
 * 这个factory可以返回一个独立contained对象的实例（Prototype design pattern），或者一个共享实例（a superior
 * alternative to the Singleton design
 * pattern,这种情况下，在factory范围内，这个实例是单例的）。返回哪一种实例，取决于bean
 * factory的配置，API是相同的。从Spring 2.0开始，根据具体application
 * context的实现，可以有更多的范围可以选择。（例如，在Web环境中的request和session范围）。
 * <p>
 * 这种方式的目标是把BeanFactory作为应用组件的中心注册器，将应用组件的配置信息进行集中（例如创建独立对象时，不再需要读取属性文件）。
 * 这种方式优点的更多讨论，请参看《Expert One-on-One J2EE Design and Development》第四章和第十一章。
 * <p>
 * 注意一般情况下，最好通过依赖注入
 * （push配置），通过setter和构造方法去配置应用中的对象，而不是通过任何形式的pull配置，例如BeanFactory
 * lookup。Spring的依赖注入功能，通过BeanFactory接口和它的子接口实现。
 * <p>
 * 通常，一个BeanFactory将从源（例如一个XML文档）装载bean的定义信息，然后使用
 * org.springframework.beans包中的类配置bean
 * 。尽管如此，如果需要，一个实现类可以直接在Java代码中，返回它创建的Java对象。
 * bean定义应该保存在哪里，并没有严格的限制，可以是LDAP、RDBMS、XML、属性文件等等。鼓励实现类支持bean之间的引用（依赖注入）。
 * <p>
 * 与{@link ListableBeanFactory}中的方法形成对比，这个接口的所有方法，will also check parent
 * factories if this is a {@link HierarchicalBeanFactory}
 * 。如果一个bean在则会个工厂实例中没有找到，将ask直接父工厂。工厂中同名的bean将override任何父工厂的同名bean。
 * <p>
 * 
 * Bean factory的实现类应该尽可能的支持标准bean生命周期接口。完整的初始化方法和顺序如下：<br/>
 * 1. BeanNameAware's <code>setBeanName</code><br>
 * 2. BeanClassLoaderAware's <code>setBeanClassLoader</code><br>
 * 3. BeanFactoryAware's <code>setBeanFactory</code><br>
 * 4. ResourceLoaderAware's <code>setResourceLoader</code> (仅在运行于应用上下文时适用)<br>
 * 5. ApplicationEventPublisherAware's <code>setApplicationEventPublisher</code>
 * (仅在运行于应用上下文时适用)<br>
 * 6. MessageSourceAware's <code>setMessageSource</code> (仅在运行于应用上下文时适用)<br>
 * 7. ApplicationContextAware's <code>setApplicationContext</code>
 * (仅在运行于应用上下文时适用)<br>
 * 8. ServletContextAware's <code>setServletContext</code> (仅在运行于应用上下文时适用)<br>
 * 9. <code>postProcessBeforeInitialization</code> methods of BeanPostProcessors
 * <br>
 * 10. InitializingBean's <code>afterPropertiesSet</code><br>
 * 11. 设置的init-method定义。<br/>
 * 12. <code>postProcessAfterInitialization</code> methods of BeanPostProcessors
 * <p>
 * 在bean factory关闭时，执行以下生命周期方法：<br/>
 * 1. DisposableBean's <code>destroy</code><br>
 * 2. a custom destroy-method definition
 * 
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @since 13 April 2001
 * @see BeanNameAware#setBeanName
 * @see BeanClassLoaderAware#setBeanClassLoader
 * @see BeanFactoryAware#setBeanFactory
 * @see org.springframework.context.ResourceLoaderAware#setResourceLoader
 * @see org.springframework.context.ApplicationEventPublisherAware#setApplicationEventPublisher
 * @see org.springframework.context.MessageSourceAware#setMessageSource
 * @see org.springframework.context.ApplicationContextAware#setApplicationContext
 * @see org.springframework.web.context.ServletContextAware#setServletContext
 * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization
 * @see InitializingBean#afterPropertiesSet
 * @see org.springframework.beans.factory.support.RootBeanDefinition#getInitMethodName
 * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization
 * @see DisposableBean#destroy
 * @see org.springframework.beans.factory.support.RootBeanDefinition#getDestroyMethodName
 */
public interface BeanFactory {

	/**
	 * Used to dereference a {@link FactoryBean} instance and distinguish it
	 * from beans <i>created</i> by the FactoryBean. For example, if the bean
	 * named <code>myJndiObject</code> is a FactoryBean, getting
	 * <code>&myJndiObject</code> will return the factory, not the instance
	 * returned by the factory.
	 * <p>
	 * 用于复引用一个{@link FactoryBean}
	 * 对象，并和这个FactoryBean创建的bean区分。例如，如果名为myJndiObject的bean是一个FactoryBean，获取
	 * <code>&myJndiObject</code>将返回这个Factory，而不是工厂返回的实例。
	 */
	String FACTORY_BEAN_PREFIX = "&";

	/**
	 * #Comment#:这里根据bean的名字，在IOC容器中得到bean实例，这个IOC容器就是一个大的抽象工厂。
	 * <p>
	 * Return an instance, which may be shared or independent, of the specified
	 * bean.<br>
	 * 返回指定bean的一个实例，可以是共享的或者独立的。
	 * <p>
	 * This method allows a Spring BeanFactory to be used as a replacement for
	 * the Singleton or Prototype design pattern. Callers may retain references
	 * to returned objects in the case of Singleton beans.
	 * <p>
	 * 这个方法允许使用一个Spring
	 * BeanFactory作为单例模式或者原型模式的替代品。在单例bean的情况下，caller可以保持对返回对象的引用。
	 * <p>
	 * Translates aliases back to the corresponding canonical bean name. Will
	 * ask the parent factory if the bean cannot be found in this factory
	 * instance.
	 * 
	 * @param name
	 *            the name of the bean to retrieve
	 * @return an instance of the bean
	 * @throws NoSuchBeanDefinitionException
	 *             if there is no bean definition with the specified name
	 * @throws BeansException
	 *             if the bean could not be obtained
	 */
	Object getBean(String name) throws BeansException;

	/**
	 * #Comment#：这里根据bean的名字和Class类型来得到bean实例，和上面的方法不同在于它会抛出异常：
	 * 如果根据名字取得的bean实例的Class类型和需要的不同的话。
	 * <p/>
	 * 返回指定bean的一个实例，可以是共享的或者独立的。
	 * <p>
	 * Behaves the same as {@link #getBean(String)}, but provides a measure of
	 * type safety by throwing a BeanNotOfRequiredTypeException if the bean is
	 * not of the required type. This means that ClassCastException can't be
	 * thrown on casting the result correctly, as can happen with
	 * {@link #getBean(String)}.<br/>
	 * 与{@link #getBean(String)}
	 * 方法类似，但是提供了类型安全型,如果bean不是指定类型，抛出BeanNotOfRequiredTypeException。
	 * <p>
	 * Translates aliases back to the corresponding canonical bean name. Will
	 * ask the parent factory if the bean cannot be found in this factory
	 * instance.
	 * 
	 * @param name
	 *            the name of the bean to retrieve
	 * @param requiredType
	 *            type the bean must match. Can be an interface or superclass of
	 *            the actual class, or <code>null</code> for any match. For
	 *            example, if the value is <code>Object.class</code>, this
	 *            method will succeed whatever the class of the returned
	 *            instance.
	 * @return an instance of the bean
	 * @throws BeanNotOfRequiredTypeException
	 *             if the bean is not of the required type
	 * @throws NoSuchBeanDefinitionException
	 *             if there's no such bean definition
	 * @throws BeansException
	 *             if the bean could not be created
	 */
	Object getBean(String name, Class requiredType) throws BeansException;

	/**
	 * #Comment#:这里提供对bean的检索，看看是否在IOC容器有这个名字的bean
	 * <p>
	 * 此beanfactory是否包含给定名称的bean，即，{@link #getBean}方法是否可以获取bean实例？
	 * <p>
	 * Translates aliases back to the corresponding canonical bean name. Will
	 * ask the parent factory if the bean cannot be found in this factory
	 * instance.
	 * 
	 * @param name
	 *            the name of the bean to query
	 * @return whether a bean with the given name is defined
	 */
	boolean containsBean(String name);

	/**
	 * 这个bean是共享单例么？如果是，{@link #getBean}将一直返回同一个实例。
	 * <p>
	 * Note: This method returning <code>false</code> does not clearly indicate
	 * independent instances. It indicates non-singleton instances, which may
	 * correspond to a scoped bean as well. Use the {@link #isPrototype}
	 * operation to explicitly check for independent instances.
	 * <p>
	 * Translates aliases back to the corresponding canonical bean name. Will
	 * ask the parent factory if the bean cannot be found in this factory
	 * instance.
	 * 
	 * @param name
	 *            the name of the bean to query
	 * @return whether this bean corresponds to a singleton instance
	 * @throws NoSuchBeanDefinitionException
	 *             if there is no bean with the given name
	 * @see #getBean
	 * @see #isPrototype
	 */
	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

	/**
	 * 这个bean是原型么？如果是{@link #getBean}方法将始终返回单独实例
	 * <p>
	 * Note: This method returning <code>false</code> does not clearly indicate
	 * a singleton object. It indicates non-independent instances, which may
	 * correspond to a scoped bean as well. Use the {@link #isSingleton}
	 * operation to explicitly check for a shared singleton instance.
	 * <p>
	 * Translates aliases back to the corresponding canonical bean name. Will
	 * ask the parent factory if the bean cannot be found in this factory
	 * instance.
	 * 
	 * @param name
	 *            the name of the bean to query
	 * @return whether this bean will always deliver independent instances
	 * @throws NoSuchBeanDefinitionException
	 *             if there is no bean with the given name
	 * @since 2.0.3
	 * @see #getBean
	 * @see #isSingleton
	 */
	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

	/**
	 * Check whether the bean with the given name matches the specified type.
	 * More specifically, check whether a {@link #getBean} call for the given
	 * name would return an object that is assignable to the specified target
	 * type.<br/>
	 * 验证指定名称的bean是否和指定的类型相符。
	 * <p>
	 * Translates aliases back to the corresponding canonical bean name. Will
	 * ask the parent factory if the bean cannot be found in this factory
	 * instance.
	 * 
	 * @param name
	 *            the name of the bean to query
	 * @param targetType
	 *            the type to match against
	 * @return <code>true</code> if the bean type matches, <code>false</code> if
	 *         it doesn't match or cannot be determined yet
	 * @throws NoSuchBeanDefinitionException
	 *             if there is no bean with the given name
	 * @since 2.0.1
	 * @see #getBean
	 * @see #getType
	 */
	boolean isTypeMatch(String name, Class targetType)
			throws NoSuchBeanDefinitionException;

	/**
	 * #Comment#:这里对得到bean实例的Class类型
	 * <p>
	 * Determine the type of the bean with the given name. More specifically,
	 * determine the type of object that {@link #getBean} would return for the
	 * given name.<br/>
	 * 获得指定名称bean的类型。
	 * <p>
	 * For a {@link FactoryBean}, return the type of object that the FactoryBean
	 * creates, as exposed by {@link FactoryBean#getObjectType()}.
	 * <p>
	 * Translates aliases back to the corresponding canonical bean name. Will
	 * ask the parent factory if the bean cannot be found in this factory
	 * instance.
	 * 
	 * @param name
	 *            the name of the bean to query
	 * @return the type of the bean, or <code>null</code> if not determinable
	 * @throws NoSuchBeanDefinitionException
	 *             if there is no bean with the given name
	 * @since 1.1.2
	 * @see #getBean
	 * @see #isTypeMatch
	 */
	Class getType(String name) throws NoSuchBeanDefinitionException;

	/**
	 * #Comment#:这里得到bean的别名，如果根据别名检索，那么其原名也会被检索出来
	 * <p>
	 * Return the aliases for the given bean name, if any. All of those aliases
	 * point to the same bean when used in a {@link #getBean} call.<br/>
	 * 返回指定名称bean的别名。
	 * <p>
	 * If the given name is an alias, the corresponding original bean name and
	 * other aliases (if any) will be returned, with the original bean name
	 * being the first element in the array.
	 * <p>
	 * Will ask the parent factory if the bean cannot be found in this factory
	 * instance.
	 * 
	 * @param name
	 *            the bean name to check for aliases
	 * @return the aliases, or an empty array if none
	 * @see #getBean
	 */
	String[] getAliases(String name);

}
